use tauri::Window;
use tokio::sync::Mutex;
use tokio_serial::available_ports;

use crate::{
    conn::serial_port::SerialPort,
    error::{new_static_err, AppErr},
};

use self::serial_port::SharedPort;

mod serial_port;

static PORT: Mutex<Option<SharedPort>> = Mutex::const_new(None);

#[tauri::command]
pub fn get_current_serial_ports() -> Result<Vec<String>, AppErr> {
    let names: Vec<String> = available_ports()?
        .into_iter()
        .map(|item| item.port_name)
        .collect();
    Ok(names)
}

#[tauri::command]
pub async fn serial_port_open(name: String, baud_rate: u32, window: Window) -> Result<(), AppErr> {
    let mut port = PORT.lock().await;
    if port.is_some() {
        return new_static_err("串口已经打开");
    }
    let new_port = SerialPort::new(&name, baud_rate, window)?;
    *port = Some(new_port);
    Ok(())
}

#[tauri::command]
pub async fn serial_port_write(buf: Box<[u8]>) -> Result<(), AppErr> {
    let port = PORT.lock().await;
    match &*port {
        Some(v) => {
            v.write(&buf).await?;
        }
        None => {
            return new_static_err("串口没有打开");
        }
    };

    Ok(())
}

#[tauri::command]
pub async fn serial_port_is_open() -> bool {
    PORT.lock().await.is_some()
}

#[tauri::command]
pub async fn serial_port_close() -> Result<(), AppErr> {
    let mut v = PORT.lock().await;
    match &*v {
        Some(v) => {
            v.close();
        }
        None => {}
    };
    *v = None;

    Ok(())
}
